﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib.Debugging;
using alib.Enumerable;
using alib.Collections;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class EntrySet : identity_base,
		ρρTdlHash
	{
		public EntrySet(EntryMgr em)
			: base(em)
		{
			this.em = em;
		}

		protected readonly EntryMgr em;
		public EntryMgr EntryMgr { get { return em; } }

		///////////////////////////////////////////////////////////////////////
		///
		long tdl_hash;
		public void update_hash(long h) { tdl_hash ^= h; }
		public long TdlHash { get { return tdl_hash; } }
		///
		///////////////////////////////////////////////////////////////////////
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{arr.GetType().GetElementType().Name,nq}[{Count}]")]
	public abstract class EntrySet<T> : EntrySet, IReadOnlyList<T>
		where T : Entry
	{
		public EntrySet(EntryMgr em)
			: base(em)
		{
			this.loader = new RefList<T>();
		}

		T[] arr;

		public T[] __get_arr()
		{
			if (arr == null)
				throw new Exception("not frozen yet");
			return arr;
		}

		RefList<T> loader;

		public void Add(/* T */ Entry e)
		{
			loader.Add((T)e);
		}

		public void Freeze()
		{
			arr = Interlocked.Exchange(ref loader, null).GetTrimmed();
		}

		public T this[int index] { get { return arr[index]; } }

		public int Count { get { return arr.Length; } }

		public IEnumerator<T> GetEnumerator() { return arr.Enumerator(); }

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return arr.GetEnumerator(); }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	[DebuggerDisplay("SyntaxRules: {sr.Length}  LexicalRules: {lr.Length}")]
	public sealed class RuleSet : IReadOnlyList<Rule>
	{
		public RuleSet(EntryMgr em)
		{
			this.sr = em._syntax_rules.__get_arr();
			this.lr = em._lexical_rules.__get_arr();
			this.count = sr.Length + lr.Length;
		}

		readonly SyntaxRule[] sr;
		readonly LexicalRule[] lr;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		readonly int count;

		public int Count { get { return count; } }

		public Rule this[int index]
		{
			get
			{
				int i2 = index - sr.Length;
				return i2 < 0 ? (Rule)sr[index] : lr[i2];
			}
		}

		public int IndexOf(Rule r)
		{
			int ix = r.SubIndex;
			if (r is LexicalRule)
				ix += sr.Length;
#if DEBUG
			if (this[ix] != r)
				throw new Exception();
#endif
			return ix;
		}

		public IEnumerator<Rule> GetEnumerator()
		{
			int i;
			for (i = 0; i < sr.Length; i++)
				yield return sr[i];
			for (i = 0; i < lr.Length; i++)
				yield return lr[i];
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	public sealed class SyntaxRuleSet : EntrySet<SyntaxRule>
	{
		public SyntaxRuleSet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class LexicalRuleSet : EntrySet<LexicalRule>
	{
		public LexicalRuleSet(EntryMgr em)
			: base(em)
		{
		}
		public int c_morphological;
		public int c_spelling_change;
	};

	public sealed class LexicalEntrySet : EntrySet<LexicalEntry>
	{
		public LexicalEntrySet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class StartSymbolSet : EntrySet<StartSymbol>
	{
		public StartSymbolSet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class GenericLexicalEntrySet : EntrySet<GenericLexicalEntry>
	{
		public GenericLexicalEntrySet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class TriggerRuleSet : EntrySet<TriggerRule>
	{
		public TriggerRuleSet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class TokenMappingRuleSet : EntrySet<TokenMappingRule>
	{
		public TokenMappingRuleSet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class LexicalFilteringRuleSet : EntrySet<LexicalFilteringRule>
	{
		public LexicalFilteringRuleSet(EntryMgr em)
			: base(em)
		{
		}
	};

	public sealed class NodeLabelSet : EntrySet<NodeLabel>
	{
		public NodeLabelSet(EntryMgr em)
			: base(em)
		{
		}
	};
}
